﻿using System;
using System.Collections.Generic;
using System.Data;

namespace GeneratePE {
    public class EntityHelper {

        #region Property

        // 表
        public DataTable Table { get; set; }
        /// <summary>
        /// namespace
        /// </summary> 
        public string NameSpace { get; set; }
        /// <summary>
        /// class name
        /// </summary> 
        public string ClassName { get; set; }
        /// <summary>
        /// Use column Remarks to fill in summary
        /// </summary>
        public bool IsSummary { get; set; }
        /// <summary>
        /// Use DataReader to fill in entity class
        /// </summary>
        public bool IsDataReader { get; set; }

        #endregion

        #region Private methods

        // 通过字段类型，返回在C#中的类型，Sql server
        private string SqlDbTypeToCSharpType(string type) {
            string returnValue = string.Empty;
            switch (type.ToLower()) {
                case "smallint": returnValue = "Int16"; break;
                case "int": returnValue = "Int32"; break;
                case "real": returnValue = "Single"; break;
                case "float": returnValue = "Double"; break;
                case "money": returnValue = "Decimal"; break;
                case "smallmoney": returnValue = "Decimal"; break;
                case "bit": returnValue = "Boolean"; break;
                case "decimal": returnValue = "Decimal"; break;
                case "number": returnValue = "Decimal"; break;
                case "tinyint": returnValue = "SByte"; break;
                case "bigint": returnValue = "Int64"; break;
                case "timestamp": returnValue = "Byte[]"; break;
                case "binary": returnValue = "Byte[]"; break;
                case "image": returnValue = "Byte[]"; break;
                case "text": returnValue = "String"; break;
                case "ntext": returnValue = "String"; break;
                case "numeric": returnValue = "Decimal"; break;
                case "date": returnValue = "DateTime"; break;
                case "datetime": returnValue = "DateTime"; break;
                case "smalldatetime": returnValue = "DateTime"; break;
                case "sql_variant": returnValue = "Object"; break;
                case "xml": returnValue = "String"; break;
                case "varchar": returnValue = "String"; break;
                case "char": returnValue = "String"; break;
                case "nchar": returnValue = "String"; break;
                case "nvarchar": returnValue = "String"; break;
                case "varbinary": returnValue = "Byte[]"; break;
                case "uniqueidentifier": returnValue = "Guid"; break;
            }
            return returnValue;
        }
        // 通过字段类型，返回在C#中的类型，Access
        private string AccDbTypeToCSharpType(string type) {
            string returnValue = string.Empty;
            switch (type.ToLower()) {
                case "bigint": returnValue = "Int64"; break;
                case "binary": returnValue = "Byte[]"; break;
                case "boolean": returnValue = "Boolean"; break;
                case "bstr": returnValue = "String"; break;
                case "char": returnValue = "String"; break;
                case "currency": returnValue = "Decimal"; break;
                case "date": returnValue = "DateTime"; break;
                case "dbdate": returnValue = "DateTime"; break;
                //case "dbtime": returnValue = ""; break;
                case "dbtimestamp": returnValue = "DateTime"; break;
                case "decimal": returnValue = "Decimal"; break;
                case "double": returnValue = "Double"; break;
                case "empty": break;
                case "error": returnValue = "Exception"; break;
                case "filetime": returnValue = "DateTime"; break;
                case "guid": returnValue = "Guid"; break;
                case "idispatch": returnValue = "Object"; break;
                case "integer": returnValue = "Int32"; break;
                case "iunknown": returnValue = "Object"; break;
                case "longvarbinary": returnValue = "Byte[]"; break;
                case "longvarchar": returnValue = "String"; break;
                case "longvarwchar": returnValue = "String"; break;
                case "numeric": returnValue = "Decimal"; break;
                case "propvariant": returnValue = "Object"; break;
                case "single": returnValue = "Single"; break;
                case "smallint": returnValue = "Int16"; break;
                case "tinyint": returnValue = "SByte"; break;
                case "unsignedbigint": returnValue = "UInt64"; break;
                case "unsignedint": returnValue = "UInt32"; break;
                case "unsignedsmallint": returnValue = "UInt16"; break;
                case "unsignedtinyint": returnValue = "Byte"; break;
                case "varbinary": returnValue = "Byte[]"; break;
                case "varchar": returnValue = "String"; break;
                case "variant": returnValue = "Object"; break;
                case "varnumeric": returnValue = "Decimal"; break;
                case "varwChar": returnValue = "String"; break;
                case "wchar": returnValue = "String"; break;
            }
            return returnValue;
        }
        // 首字母大写
        private string FirstLetterUpper(string str) {
            if (string.IsNullOrEmpty(str)) { return string.Empty; }
            if (str.Length > 1) {
                return str.Substring(0, 1).ToUpper() + str.Substring(1);
            }
            return str.ToUpper();
            // return System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(str);
        }
        // 获取 list 中指定的行
        private List<string> GetListAppointRows(List<string> list, int startLineNum, int endLineNum) {
            int[] lineNums = new int[endLineNum - startLineNum + 1];
            for (int i = 0; i <= endLineNum - startLineNum; i++) {
                lineNums[i] = startLineNum + i;
            }
            return this.GetListAppointRows(list, lineNums);
        }
        // 获取 list 中指定的行
        private List<string> GetListAppointRows(List<string> list, params int[] lineNums) {
            List<string> resultList = new List<string>(lineNums.Length);
            foreach (int index in lineNums) {
                if (index - 1 > list.Count - 1 || index - 1 < 0) { return new List<string>(); }
                resultList.Add(list[index - 1]);
            }
            return resultList;
        }
        // 连接 list
        private string JoinList(params List<string>[] lists) {
            string result = string.Empty;
            foreach (List<string> list in lists) {
                if (list.Count > 0) {
                    result += string.Join(FormatSymbol.CrLf, list.ToArray());
                    result += FormatSymbol.CrLf;
                }
            }
            return result;
        }
        // 是否能为空值
        private bool IsAllowNullable(string type) {
            string[] allowNullable = new string[] { "Int16", "Int32", "Single", "Double", "Decimal", "Boolean", "Int64", "SByte", "DateTime" };
            foreach (string s in allowNullable) {
                if (s == type) {
                    return true;
                }
            }
            return false;
        }

        #endregion

        /// <summary>
        /// 生成 Entity
        /// </summary>
        /// <returns>string</returns>
        public string GenerateEntity() {
            List<string> templateList = GenerateHelper.GetTemplateContentList(Resources.Entity);
            // 替换掉全局的先
            string tempValue;
            for (int i = 0; i < templateList.Count; i++) {
                tempValue = templateList[i];
                tempValue = GenerateHelper.RegexReplace(@"\$namespace\$", tempValue, this.NameSpace);
                tempValue = GenerateHelper.RegexReplace(@"\$classname\$", tempValue, this.ClassName);
                templateList[i] = tempValue;
            }
            // 引用的命名空间，1 - 3 行
            List<string> listNamespace = this.IsDataReader
                ? this.GetListAppointRows(templateList, 1, 2, 3)
                : this.GetListAppointRows(templateList, 1);
            // 头部，4 - 11 行
            List<string> listHeader = this.IsSummary
                ? this.GetListAppointRows(templateList, 4, 11)
                : this.GetListAppointRows(templateList, 4, 5, 6, 7, 11);
            // DataReader 头部，12 - 24 行
            List<string> listDataReaderHeader = this.IsDataReader
                ? this.GetListAppointRows(templateList, 12, 24)
                : this.GetListAppointRows(templateList, 0);
            // DataReader 尾部，27 - 37 行
            List<string> listDataReaderFooter = this.IsDataReader
                ? this.GetListAppointRows(templateList, 27, 42)
                : this.GetListAppointRows(templateList, 0);
            // 循环填充 DataReader，25 - 26 行
            List<string> listEachDrProperty = this.IsDataReader
                ? this.GetListAppointRows(templateList, 25, 26)
                : this.GetListAppointRows(templateList, 0);
            // 循环填充 Property，43- 46 行
            List<string> listEachProperty = this.IsSummary
                ? this.GetListAppointRows(templateList, 43, 44, 45, 46)
                : this.GetListAppointRows(templateList, 46);
            // 尾部，42- 43 行
            List<string> listFooter = this.GetListAppointRows(templateList, 47, 48);

            // 填充需要循环产生的
            string type, name, remark, columnName;
            List<string> listResultDrProperty = new List<string>();
            List<string> listResultProperty = new List<string>();
            foreach (DataRow dr in this.Table.Rows) {
                type = GenerateHelper.IsSqlServer
                    ? this.SqlDbTypeToCSharpType(dr["Type"].ToString())
                    : this.AccDbTypeToCSharpType(dr["Type"].ToString());
                name = this.FirstLetterUpper(dr["Name"].ToString());
                remark = Convert.ToString(dr["Remark"]);
                columnName = dr["Name"].ToString();
                foreach (string sdr in listEachDrProperty) {
                    tempValue = sdr;
                    tempValue = GenerateHelper.RegexReplace(@"\$columnname\$", tempValue, columnName);
                    tempValue = GenerateHelper.RegexReplace(@"\$type\$", tempValue, type);
                    tempValue = GenerateHelper.RegexReplace(@"\$name\$", tempValue, name);
                    listResultDrProperty.Add(tempValue);
                }
                foreach (string s in listEachProperty) {
                    tempValue = s;
                    tempValue = GenerateHelper.RegexReplace(@"\$sumarrycontent\$", tempValue, remark);
                    tempValue = GenerateHelper.RegexReplace(@"\$type\$", tempValue,
                        string.Format("{0}{1}", type,
                            (bool)dr["Nullable"] && this.IsAllowNullable(type) ? "?" : string.Empty));
                    tempValue = GenerateHelper.RegexReplace(@"\$name\$", tempValue, name);
                    listResultProperty.Add(tempValue);
                }
            }
            return this.JoinList(
                listNamespace, listHeader,
                listDataReaderHeader, listResultDrProperty, listDataReaderFooter,
                listResultProperty, listFooter);
        }
        /// <summary>
        /// 生成参数
        /// </summary>
        /// <param name="IsSqlServer">是 SqlServer 或 Access</param>
        /// <returns>string</returns>
        public string GenerateParameters() {
            List<string> templateList = GenerateHelper.GetTemplateContentList(Resources.Parameters);
            List<string> entityList = this.GetListAppointRows(templateList, 1);
            entityList[0] = GenerateHelper.RegexReplace(@"\$classname\$", entityList[0], this.ClassName);
            List<string> paramsList = GenerateHelper.IsSqlServer
                ? this.GetListAppointRows(templateList, 3, 4, 5)
                : this.GetListAppointRows(templateList, 7, 8, 9);
            // 填充需要循环产生的
            string cSharpType, type, length, name, columnName, tempValue;
            List<string> listResult = new List<string>();
            listResult.Add(paramsList[0]);
            foreach (DataRow dr in this.Table.Rows) {
                type = dr["Type"].ToString();
                cSharpType = GenerateHelper.IsSqlServer
                    ? this.SqlDbTypeToCSharpType(type)
                    : this.AccDbTypeToCSharpType(type);
                length = Convert.ToString(dr["Length"]);
                name = this.FirstLetterUpper(dr["Name"].ToString());
                columnName = dr["Name"].ToString();
                tempValue = paramsList[string.IsNullOrEmpty(length) || length == "0" ? 2 : 1];
                tempValue = GenerateHelper.RegexReplace(@"\$csharptype\$", tempValue, cSharpType);
                tempValue = GenerateHelper.RegexReplace(@"\$columnname\$", tempValue, columnName);
                tempValue = GenerateHelper.RegexReplace(@"\$length\$", tempValue, length);
                tempValue = GenerateHelper.RegexReplace(@"\$type\$", tempValue, type);
                tempValue = GenerateHelper.RegexReplace(@"\$name\$", tempValue, name);
                listResult.Add(tempValue);
            }
            return this.JoinList(entityList, listResult);
        }
        /// <summary>
        /// 生成参数
        /// </summary>
        /// <returns>string</returns>
        public string GenerateParametersStand() {
            List<string> templateList = GenerateHelper.GetTemplateContentList(Resources.Parameters);
            List<string> entityList = this.GetListAppointRows(templateList, 1);
            entityList[0] = GenerateHelper.RegexReplace(@"\$classname\$", entityList[0], this.ClassName);
            List<string> paramsList = GenerateHelper.IsSqlServer
                ? this.GetListAppointRows(templateList, 11, 12)
                : this.GetListAppointRows(templateList, 14, 15);
            // 填充需要循环产生的
            string cSharpType, type, length, name, nullAble, columnName, tempValue;
            List<string> listResult = new List<string>();
            listResult.Add(paramsList[0]);
            foreach (DataRow dr in this.Table.Rows) {
                type = dr["Type"].ToString();
                cSharpType = GenerateHelper.IsSqlServer
                    ? this.SqlDbTypeToCSharpType(type)
                    : this.AccDbTypeToCSharpType(type);
                length = Convert.ToString(dr["Length"]);
                name = this.FirstLetterUpper(dr["Name"].ToString());
                nullAble = Convert.ToBoolean(dr["Nullable"]).ToString().ToLower();
                columnName = dr["Name"].ToString();
                for (int i = 1; i < paramsList.Count; i++) {
                    if ((string.IsNullOrEmpty(length) || length == "0") && i == 4) { continue; }
                    tempValue = paramsList[i];
                    tempValue = GenerateHelper.RegexReplace(@"\$csharptype\$", tempValue, cSharpType);
                    tempValue = GenerateHelper.RegexReplace(@"\$columnname\$", tempValue, columnName);
                    tempValue = GenerateHelper.RegexReplace(@"\$length\$", tempValue, string.IsNullOrEmpty(length) ? string.Empty : "," + length);
                    tempValue = GenerateHelper.RegexReplace(@"\$type\$", tempValue, type);
                    tempValue = GenerateHelper.RegexReplace(@"\$name\$", tempValue, name);
                    tempValue = GenerateHelper.RegexReplace(@"\$nullable\$", tempValue, nullAble);
                    listResult.Add(tempValue);
                }
            }
            return this.JoinList(entityList, listResult);
        }
    }
}
